<template>
  <div class="chitchat" >
    <div id="editDivBody" :class="isInspection?'Inspection':''">
      <div style="margin-bottom:12px">
        <template v-for="(item,index) in optionaParams">
          <el-button class="nickname" @click ="addStrBtnFun(item)" :key="index">{{item}}</el-button>
        </template>
      </div>
      <div class="headPortrait" v-if="uploadHtml">
        <div :disabled="textSize >= maxNum" ref="editInput" class="edit" :id="id" contenteditable="true" @input="editInput" placeholder="请输入消息内容" v-html="innerHtml" @paste="handlePaste"></div>
      </div>

    </div>
    <div class="limit">{{textSize}}/{{maxNum}}</div>
    <p v-if="isInspection" class="Contentfilling">请填写消息内容</p>
  </div>
</template>

<script>
let editDiv = null //编辑元素
let range = "" //选区
export default {
  props: {
    optionaParams: {
      type: Array,
      default:() => []
    },
    id: {
      type: String,
      default:""
    },
    initText: {
      type: String,
      default:""
    }
  },
  data () {
    return {
      // 赋值
      innerHtml:'',// 初始化赋值
      innerHtmlBf:'',//备份数据
      nowHtmlT:'',// 实时html-动态变量
      nowText:'',// 实时文本
      // 获取当前最新数据
      getDataTime:1000,
      getDataTimeInter:null,
      textSize:0,
      maxNum:500,
      isInspection:false,
      uploadHtml:true,

    }
  },
  mounted() {
    this.initEditFun()
  },
  methods:{
    initContent(innerHtml){
      if(innerHtml){
        let innerText = innerHtml.replaceAll("{",'')
        innerText = innerText.replaceAll("}",'')
        this.textSize = innerText.length
        innerHtml = innerHtml.replaceAll("{",'<span class="selColor" contenteditable="false">')
        innerHtml = innerHtml.replaceAll("}",'</span>')
        this.innerHtml = innerHtml
      }
    },
    initEditFun(){

      editDiv = document.querySelector('#'+this.id)
      editDiv.addEventListener("blur", () => {
        // 这一步是保留住edit编辑框中的选区的范围对象。
        // 否则失焦后，getSelection()方法返回的选区对象已经不再是编辑框了，已经获取不到编辑框中的范围对象了。
        range = window.getSelection()?window.getSelection().getRangeAt(0):''
      })
      document.addEventListener('selectionchange', (e) => {
        let selection = document.getSelection();
        let rangeVal = selection &&  selection.rangCount>0?selection.getRangeAt(0):''
        if (
          (rangeVal && this.hasAncestorWithId(rangeVal.commonAncestorContainer,this.id))
        ) {
          range =  window.getSelection()?window.getSelection().getRangeAt(0):''
        }
      });
    },
    // 递归判断是否有父级id = editSelDiv
    hasAncestorWithId(element, id) {
      if (!element) return false;
      if (element.id === id) return true;
      if (element.parentNode) {
        return this.hasAncestorWithId(element.parentNode, id);
      }
      return false;
    },
    editInput(e) {
      this.getNowContent() //获取最新内容
      if(e.target.children.length>0){
        this.editSpanClass()
      }
      if(e.target.innerText == ''){
        range = ''
        e.target.innerHtml = ''
        this.innerHtml = ''
        this.innerHtmlBf = ''
      }
    },
    editSpanClass(){

      let spanAll = document.querySelectorAll('#'+this.id +' .edit span')
      spanAll.forEach(item=>{
        let nowVal = item.childNodes[0].data
        if(  nowVal && this.optionaParams.indexOf(nowVal.trim()) <0 ){
          item.className = 'mrClass'
        }
      })
    },
    // 粘贴
    handlePaste(e){
      e.preventDefault(); // 阻止默认粘贴操作
      const clipboardData = e.clipboardData || window.clipboardData;
      const text = clipboardData.getData('text/plain'); // 获取纯文本内容
      document.execCommand('insertHTML', false, text); // 将文本插入 contenteditable 元素中
    },
    addStrBtnFun(Text){
      const innerText = this.$refs.editInput.innerText
      const now_length = innerText.split('\u200B').join('').length
      const length = now_length + Text.length //当前长度+按钮文字长度
      if(length > this.maxNum){
        return
      }
      const span = document.createElement("span")
      span.innerText = Text
      span.className = 'selColor'
      span.setAttribute('contenteditable', 'false');
      // 如果在页面刷新再点击编辑框之前就点击了按钮，此时range中并没有选区范围对象
      if (range === "") {
        let selection = window.getSelection()

        console.log("window.getSelection() === "+selection)
        selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素设为选中区域，并取消之前的选中区域。不包括node节点本身。
        /*
          Selection.collapseToEnd() 方法的作用是取消当前选区，并把光标定位在原选区的最末尾处，如果此时光标所处的位置是可编辑的，且它获得了焦点，则光标会在原地闪烁。
          以上selectAllChildren方法，将div中子节点全部选中，collapseToEnd方法将选中区域取消，并且将光标定位到原区的末尾。
        */
        selection.collapseToEnd()
        range = window.getSelection()?window.getSelection().getRangeAt(0):''// 无论哪一步都需要保存当前编辑框的选区对象
      }

      var containerElement = range.commonAncestorContainer;
      console.log(containerElement)
      while (containerElement && containerElement.nodeType !== 1) {
        containerElement = containerElement.parentNode;
      }
      if (containerElement.id != this.id) {
        var element = document.getElementById(this.id);
        range.selectNode(element);
        var selection = window.getSelection();
        selection.selectAllChildren(element)
        selection.collapseToEnd()
        range = window.getSelection()?window.getSelection().getRangeAt(0):''
      }
      let sel = window.getSelection()
      let space = document.createTextNode('\u200B'); // 创建 &ZeroWidthSpace; 实体字符节点
      range.insertNode(space)
      range.insertNode(span) // insertNode方法，在range选区开头插入一个节点
      /*
      removeAllRanges方法：删除之前的所有选区。
      这一步的意义：因为当我们点击其他区域时，选区对象已经改变，不再是编辑框中的选区对象，这时候我们接下来的操作都不会符合我们想象中的样子
     */
      sel.removeAllRanges()
      sel.addRange(range) // 这一步就是添加当前区域对象到选区对象中，所以选区对象会再次指向编辑框中的选区，不会出现别的错误操作。
      sel.collapseToEnd()

      this.editSpanClass()
      this.getNowContent()
    },
    resevedSelDiv(){
      range = document.createRange();
      range.selectNode(document.querySelector('#'+this.id ).lastChild);
      window.getSelection().removeAllRanges();
      window.getSelection().addRange(range);
      let selection = window.getSelection()
      selection.selectAllChildren(editDiv)
      selection.collapseToEnd()
      range = window.getSelection()?window.getSelection().getRangeAt(0):''
    },
    // 获取最新的内容
    getNowContent(){
      const innerText = this.$refs.editInput.innerText
      const length = innerText.split('\u200B').join('').length
      if(length<= this.maxNum){
        this.innerHtmlBf = this.$refs.editInput.innerHTML
        this.nowText = this.$refs.editInput.innerText
        this.textSize = length
        this.isInspection=false
      }else{
        this.uploadHtml = false
        this.$nextTick(() => {
          this.innerHtml = this.innerHtmlBf
          this.uploadHtml = true
          setTimeout(()=>{
            this.resevedSelDiv()
          },1)
        });
      }
      this.getSpecialContent()
    },
    // 获取带符号的内容
    getSpecialContent(){
      let selectorName = '#'+this.id + ' span';
      console.log(selectorName)
      let spanAll = document.querySelectorAll(selectorName)
      let mrArr = []
      console.log(spanAll)
      spanAll.forEach(item=>{
        let nowVal = item.childNodes[0].data
        mrArr.push(nowVal)
        console.log(item)
        console.log(nowVal)
        if(item.className == 'selColor'){
          item.childNodes[0].data = '{'+nowVal+'}'
        }
      })
      this.nowHtmlT = this.$refs.editInput.innerText
      spanAll.forEach((item,i)=>{
        item.childNodes[0].data = mrArr[i]
      })
      this.$emit('nowHtmlT',this.nowHtmlT)
    },
    replaceText(text, oldStr, newStr) {
      // 检查是否为字符串类型
      if (typeof text !== 'string') {
        text = String(text);
      }
      // 替换字符
      text = text.replace(new RegExp(oldStr, "g"), newStr);
      // 处理子级
      if (text.includes('<') && text.includes('>')) {
        const start = text.indexOf('<');
        const end = text.indexOf('>') + 1;
        let subtext = text.substring(start, end);
        while (start >= 0 && end >= 0 && end > start) {
          const subtextNew = replaceText(subtext, oldStr, newStr);
          text = text.substring(0, start) + subtextNew + text.substring(end);
          subtext = text.substring(start, end);
        }
      }
      return text;
    },
    checkIsNonData(){
      const innerText = this.$refs.editInput.innerText
      const length = innerText.split('\u200B').join('').length
      if(innerText == '' || innerText == '\n' || length == 0){
        this.isInspection = true
      }else{
        this.isInspection = false
      }
    },
  },
  beforeDestroy() {
    editDiv = null //编辑元素
    range = "" //选区
  }
}
</script>
<style lang="scss" scoped>
.edit{
  width: 100%;
  height:auto;
  min-height: 130px;
  max-height: 135px;
  overflow-y: auto;
}
.edit:focus {
  outline: 0;
  border-color: #409EFF;
}
#editDivBody{
  width: 100%;
  //height:203px;
  overflow-y: auto;
  background: #FFF;
  border-radius: 4px;
  border: 1px solid #DCDEE6;
  padding: 12px 12px 20px 13px;
  margin-left: 8px;
  position: relative;
}
::-webkit-scrollbar {
  /*滚动条整体样式*/
  width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
  height: 1px;
}

::-webkit-scrollbar-thumb {
  /*滚动条里面小方块*/
  border-radius: 5px;
  background-color:  #D8D8D8;
}

::-webkit-scrollbar-track {
  background-color: #f6f6f6;
}
::-webkit-scrollbar-thumb,
::-webkit-scrollbar-track {
  border: 0;
}

.Inspection{
  border: 1px solid #FF4949!important;
}
.nickname{
  background: #FFFFFF;
  border-radius: 4px;
  border: 1px solid #DCDFE6;
  font-size: 12px;
  font-weight: 400;
  color: #1890FF;
  line-height: 17px;
  padding: 4px 8px;
}
.chitchat{
  display: flex;
  position: relative;
  width: 100%;
}
.Contentfilling{
  width: 84px;
  height: 17px;
  font-size:12px;
  line-height: 17px;
  color: #FF4949;
  position: absolute;
  bottom: -18px;
  left: 41px;
  margin: 0;
}
::v-deep font{
  color: #000;
}
font{
  color: #000;
}
::v-deep .selColor{
  color: #1890FF;
  font-size: 14px;
}
 .selColor{
  color: #1890FF;
  font-size: 14px;
}

::v-deep .mrClass{
  color: #000;
  font-size: 14px;
}
.mrClass{
  color: #000;
  font-size: 14px;
}
.limit{
  position: absolute;
  bottom: 0;
  right:0;
  padding: 0 8px;
  line-height: 22px;
  font-size: 14px;
  color: #86909C;
}

.headPortrait{
  position: relative;
  font-size: 14px;
}
</style>
